1   /*
2    * Copyright (C) 2009 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import com.google.common.annotations.GwtCompatible;
22  import com.google.common.base.MoreObjects;
23  
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.Comparator;
28  import java.util.LinkedHashMap;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Map.Entry;
32  
33  import javax.annotation.Nullable;
34  
35  /**
36   * An immutable {@link SetMultimap} with reliable user-specified key and value
37   * iteration order. Does not permit null keys or values.
38   *
39   * <p>Unlike {@link Multimaps#unmodifiableSetMultimap(SetMultimap)}, which is
40   * a <i>view</i> of a separate multimap which can still change, an instance of
41   * {@code ImmutableSetMultimap} contains its own data and will <i>never</i>
42   * change. {@code ImmutableSetMultimap} is convenient for
43   * {@code public static final} multimaps ("constant multimaps") and also lets
44   * you easily make a "defensive copy" of a multimap provided to your class by
45   * a caller.
46   *
47   * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
48   * it has no public or protected constructors. Thus, instances of this class
49   * are guaranteed to be immutable.
50   *
51   * <p>See the Guava User Guide article on <a href=
52   * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
53   * immutable collections</a>.
54   *
55   * @author Mike Ward
56   * @since 2.0 (imported from Google Collections Library)
57   */
58  @GwtCompatible(serializable = true, emulated = true)
59  public class ImmutableSetMultimap<K, V>
60      extends ImmutableMultimap<K, V>
61      implements SetMultimap<K, V> {
62  
63    /** Returns the empty multimap. */
64    // Casting is safe because the multimap will never hold any elements.
65    @SuppressWarnings("unchecked")
66    public static <K, V> ImmutableSetMultimap<K, V> of() {
67      return (ImmutableSetMultimap<K, V>) EmptyImmutableSetMultimap.INSTANCE;
68    }
69  
70    /**
71     * Returns an immutable multimap containing a single entry.
72     */
73    public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1) {
74      ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
75      builder.put(k1, v1);
76      return builder.build();
77    }
78  
79    /**
80     * Returns an immutable multimap containing the given entries, in order.
81     * Repeated occurrences of an entry (according to {@link Object#equals}) after
82     * the first are ignored.
83     */
84    public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1, K k2, V v2) {
85      ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
86      builder.put(k1, v1);
87      builder.put(k2, v2);
88      return builder.build();
89    }
90  
91    /**
92     * Returns an immutable multimap containing the given entries, in order.
93     * Repeated occurrences of an entry (according to {@link Object#equals}) after
94     * the first are ignored.
95     */
96    public static <K, V> ImmutableSetMultimap<K, V> of(
97        K k1, V v1, K k2, V v2, K k3, V v3) {
98      ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
99      builder.put(k1, v1);
100     builder.put(k2, v2);
101     builder.put(k3, v3);
102     return builder.build();
103   }
104 
105   /**
106    * Returns an immutable multimap containing the given entries, in order.
107    * Repeated occurrences of an entry (according to {@link Object#equals}) after
108    * the first are ignored.
109    */
110   public static <K, V> ImmutableSetMultimap<K, V> of(
111       K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
112     ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
113     builder.put(k1, v1);
114     builder.put(k2, v2);
115     builder.put(k3, v3);
116     builder.put(k4, v4);
117     return builder.build();
118   }
119 
120   /**
121    * Returns an immutable multimap containing the given entries, in order.
122    * Repeated occurrences of an entry (according to {@link Object#equals}) after
123    * the first are ignored.
124    */
125   public static <K, V> ImmutableSetMultimap<K, V> of(
126       K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
127     ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
128     builder.put(k1, v1);
129     builder.put(k2, v2);
130     builder.put(k3, v3);
131     builder.put(k4, v4);
132     builder.put(k5, v5);
133     return builder.build();
134   }
135 
136   // looking for of() with > 5 entries? Use the builder instead.
137 
138   /**
139    * Returns a new {@link Builder}.
140    */
141   public static <K, V> Builder<K, V> builder() {
142     return new Builder<K, V>();
143   }
144 
145   /**
146    * Multimap for {@link ImmutableSetMultimap.Builder} that maintains key
147    * and value orderings and performs better than {@link LinkedHashMultimap}.
148    */
149   private static class BuilderMultimap<K, V> extends AbstractMapBasedMultimap<K, V> {
150     BuilderMultimap() {
151       super(new LinkedHashMap<K, Collection<V>>());
152     }
153     @Override Collection<V> createCollection() {
154       return Sets.newLinkedHashSet();
155     }
156     private static final long serialVersionUID = 0;
157   }
158 
159   /**
160    * A builder for creating immutable {@code SetMultimap} instances, especially
161    * {@code public static final} multimaps ("constant multimaps"). Example:
162    * <pre>   {@code
163    *
164    *   static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
165    *       new ImmutableSetMultimap.Builder<String, Integer>()
166    *           .put("one", 1)
167    *           .putAll("several", 1, 2, 3)
168    *           .putAll("many", 1, 2, 3, 4, 5)
169    *           .build();}</pre>
170    *
171    * <p>Builder instances can be reused; it is safe to call {@link #build} multiple
172    * times to build multiple multimaps in series. Each multimap contains the
173    * key-value mappings in the previously created multimaps.
174    *
175    * @since 2.0 (imported from Google Collections Library)
176    */
177   public static final class Builder<K, V>
178       extends ImmutableMultimap.Builder<K, V> {
179     /**
180      * Creates a new builder. The returned builder is equivalent to the builder
181      * generated by {@link ImmutableSetMultimap#builder}.
182      */
183     public Builder() {
184       builderMultimap = new BuilderMultimap<K, V>();
185     }
186 
187     /**
188      * Adds a key-value mapping to the built multimap if it is not already
189      * present.
190      */
191     @Override public Builder<K, V> put(K key, V value) {
192       builderMultimap.put(checkNotNull(key), checkNotNull(value));
193       return this;
194     }
195 
196     /**
197      * Adds an entry to the built multimap if it is not already present.
198      *
199      * @since 11.0
200      */
201     @Override public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
202       builderMultimap.put(
203           checkNotNull(entry.getKey()), checkNotNull(entry.getValue()));
204       return this;
205     }
206 
207     @Override public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
208       Collection<V> collection = builderMultimap.get(checkNotNull(key));
209       for (V value : values) {
210         collection.add(checkNotNull(value));
211       }
212       return this;
213     }
214 
215     @Override public Builder<K, V> putAll(K key, V... values) {
216       return putAll(key, Arrays.asList(values));
217     }
218 
219     @Override public Builder<K, V> putAll(
220         Multimap<? extends K, ? extends V> multimap) {
221       for (Entry<? extends K, ? extends Collection<? extends V>> entry
222           : multimap.asMap().entrySet()) {
223         putAll(entry.getKey(), entry.getValue());
224       }
225       return this;
226     }
227 
228     /**
229      * {@inheritDoc}
230      *
231      * @since 8.0
232      */
233     @Override
234     public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
235       this.keyComparator = checkNotNull(keyComparator);
236       return this;
237     }
238 
239     /**
240      * Specifies the ordering of the generated multimap's values for each key.
241      *
242      * <p>If this method is called, the sets returned by the {@code get()}
243      * method of the generated multimap and its {@link Multimap#asMap()} view
244      * are {@link ImmutableSortedSet} instances. However, serialization does not
245      * preserve that property, though it does maintain the key and value
246      * ordering.
247      *
248      * @since 8.0
249      */
250     // TODO: Make serialization behavior consistent.
251     @Override
252     public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
253       super.orderValuesBy(valueComparator);
254       return this;
255     }
256 
257     /**
258      * Returns a newly-created immutable set multimap.
259      */
260     @Override public ImmutableSetMultimap<K, V> build() {
261       if (keyComparator != null) {
262         Multimap<K, V> sortedCopy = new BuilderMultimap<K, V>();
263         List<Map.Entry<K, Collection<V>>> entries = Lists.newArrayList(
264             builderMultimap.asMap().entrySet());
265         Collections.sort(
266             entries,
267             Ordering.from(keyComparator).<K>onKeys());
268         for (Map.Entry<K, Collection<V>> entry : entries) {
269           sortedCopy.putAll(entry.getKey(), entry.getValue());
270         }
271         builderMultimap = sortedCopy;
272       }
273       return copyOf(builderMultimap, valueComparator);
274     }
275   }
276 
277   /**
278    * Returns an immutable set multimap containing the same mappings as
279    * {@code multimap}. The generated multimap's key and value orderings
280    * correspond to the iteration ordering of the {@code multimap.asMap()} view.
281    * Repeated occurrences of an entry in the multimap after the first are
282    * ignored.
283    *
284    * <p>Despite the method name, this method attempts to avoid actually copying
285    * the data when it is safe to do so. The exact circumstances under which a
286    * copy will or will not be performed are undocumented and subject to change.
287    *
288    * @throws NullPointerException if any key or value in {@code multimap} is
289    *     null
290    */
291   public static <K, V> ImmutableSetMultimap<K, V> copyOf(
292       Multimap<? extends K, ? extends V> multimap) {
293     return copyOf(multimap, null);
294   }
295 
296   private static <K, V> ImmutableSetMultimap<K, V> copyOf(
297       Multimap<? extends K, ? extends V> multimap,
298       Comparator<? super V> valueComparator) {
299     checkNotNull(multimap); // eager for GWT
300     if (multimap.isEmpty() && valueComparator == null) {
301       return of();
302     }
303 
304     if (multimap instanceof ImmutableSetMultimap) {
305       @SuppressWarnings("unchecked") // safe since multimap is not writable
306       ImmutableSetMultimap<K, V> kvMultimap
307           = (ImmutableSetMultimap<K, V>) multimap;
308       if (!kvMultimap.isPartialView()) {
309         return kvMultimap;
310       }
311     }
312 
313     ImmutableMap.Builder<K, ImmutableSet<V>> builder = ImmutableMap.builder();
314     int size = 0;
315 
316     for (Entry<? extends K, ? extends Collection<? extends V>> entry
317         : multimap.asMap().entrySet()) {
318       K key = entry.getKey();
319       Collection<? extends V> values = entry.getValue();
320       ImmutableSet<V> set = valueSet(valueComparator, values);
321       if (!set.isEmpty()) {
322         builder.put(key, set);
323         size += set.size();
324       }
325     }
326 
327     return new ImmutableSetMultimap<K, V>(
328         builder.build(), size, valueComparator);
329   }
330 
331   /**
332    * Returned by get() when a missing key is provided. Also holds the
333    * comparator, if any, used for values.
334    */
335   private final transient ImmutableSet<V> emptySet;
336 
337   ImmutableSetMultimap(ImmutableMap<K, ImmutableSet<V>> map, int size,
338       @Nullable Comparator<? super V> valueComparator) {
339     super(map, size);
340     this.emptySet = emptySet(valueComparator);
341   }
342 
343   // views
344 
345   /**
346    * Returns an immutable set of the values for the given key.  If no mappings
347    * in the multimap have the provided key, an empty immutable set is returned.
348    * The values are in the same order as the parameters used to build this
349    * multimap.
350    */
351   @Override public ImmutableSet<V> get(@Nullable K key) {
352     // This cast is safe as its type is known in constructor.
353     ImmutableSet<V> set = (ImmutableSet<V>) map.get(key);
354     return MoreObjects.firstNonNull(set, emptySet);
355   }
356 
357   private transient ImmutableSetMultimap<V, K> inverse;
358 
359   /**
360    * {@inheritDoc}
361    *
362    * <p>Because an inverse of a set multimap cannot contain multiple pairs with
363    * the same key and value, this method returns an {@code ImmutableSetMultimap}
364    * rather than the {@code ImmutableMultimap} specified in the {@code
365    * ImmutableMultimap} class.
366    *
367    * @since 11.0
368    */
369   public ImmutableSetMultimap<V, K> inverse() {
370     ImmutableSetMultimap<V, K> result = inverse;
371     return (result == null) ? (inverse = invert()) : result;
372   }
373 
374   private ImmutableSetMultimap<V, K> invert() {
375     Builder<V, K> builder = builder();
376     for (Entry<K, V> entry : entries()) {
377       builder.put(entry.getValue(), entry.getKey());
378     }
379     ImmutableSetMultimap<V, K> invertedMultimap = builder.build();
380     invertedMultimap.inverse = this;
381     return invertedMultimap;
382   }
383 
384   /**
385    * Guaranteed to throw an exception and leave the multimap unmodified.
386    *
387    * @throws UnsupportedOperationException always
388    * @deprecated Unsupported operation.
389    */
390   @Deprecated @Override public ImmutableSet<V> removeAll(Object key) {
391     throw new UnsupportedOperationException();
392   }
393 
394   /**
395    * Guaranteed to throw an exception and leave the multimap unmodified.
396    *
397    * @throws UnsupportedOperationException always
398    * @deprecated Unsupported operation.
399    */
400   @Deprecated @Override public ImmutableSet<V> replaceValues(
401       K key, Iterable<? extends V> values) {
402     throw new UnsupportedOperationException();
403   }
404 
405   private transient ImmutableSet<Entry<K, V>> entries;
406 
407   /**
408    * Returns an immutable collection of all key-value pairs in the multimap.
409    * Its iterator traverses the values for the first key, the values for the
410    * second key, and so on.
411    */
412   @Override public ImmutableSet<Entry<K, V>> entries() {
413     ImmutableSet<Entry<K, V>> result = entries;
414     return (result == null)
415         ? (entries = new EntrySet<K, V>(this))
416         : result;
417   }
418   
419   private static final class EntrySet<K, V> extends ImmutableSet<Entry<K, V>> {
420     private transient final ImmutableSetMultimap<K, V> multimap;
421     
422     EntrySet(ImmutableSetMultimap<K, V> multimap) {
423       this.multimap = multimap;
424     }
425 
426     @Override
427     public boolean contains(@Nullable Object object) {
428       if (object instanceof Entry) {
429         Entry<?, ?> entry = (Entry<?, ?>) object;
430         return multimap.containsEntry(entry.getKey(), entry.getValue());
431       }
432       return false;
433     }
434 
435     @Override
436     public int size() {
437       return multimap.size();
438     }
439 
440     @Override
441     public UnmodifiableIterator<Entry<K, V>> iterator() {
442       return multimap.entryIterator();
443     }
444 
445     @Override
446     boolean isPartialView() {
447       return false;
448     }    
449   }
450 
451   private static <V> ImmutableSet<V> valueSet(
452       @Nullable Comparator<? super V> valueComparator,
453       Collection<? extends V> values) {
454     return (valueComparator == null)
455         ? ImmutableSet.copyOf(values)
456         : ImmutableSortedSet.copyOf(valueComparator, values);
457   }
458 
459   private static <V> ImmutableSet<V> emptySet(
460       @Nullable Comparator<? super V> valueComparator) {
461     return (valueComparator == null)
462         ? ImmutableSet.<V>of()
463         : ImmutableSortedSet.<V>emptySet(valueComparator);
464   }
465 
466   @Nullable Comparator<? super V> valueComparator() {
467     return emptySet instanceof ImmutableSortedSet
468         ? ((ImmutableSortedSet<V>) emptySet).comparator()
469         : null;
470   }
471 }
472